/*
 * Copyright (c) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (c) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki.layers;

import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;

import id.duapuluhdua.dakidaki.Command;
import id.duapuluhdua.dakidaki.MainState;
import id.duapuluhdua.dakidaki.Utils;
import id.duapuluhdua.dakidaki.activities.ActivityMain;
import id.duapuluhdua.dakidaki.common.CommonActivity;
import id.duapuluhdua.dakidaki.loader.TrackItem;
import id.duapuluhdua.dakidaki.map.GeoPoint;

/**
 *
 */
public class TipFrameAltitudeGraph extends TipFrame implements Observer
{
  /** Constants */
  private final static int GRAPH_HEIGHT = 64;

  /** Fields */
  private Paint mText;
  private Paint mChartBkg;
  private Paint mChartBar;

  private Rect mRtText;  // the text area
  private Rect mRtChart;  // the chart area
  private RectF mRtBar;  // the graph bar model
  private RectF mRtDrawingBar;  // the drawn graph bar

  private ArrayList<Integer> mVecData;
  private int mAltMaxValue = 0;
  private int mAltMinValue = 0;

  private LinearGradient mBkgLinearGradient;

  // methods
  public TipFrameAltitudeGraph(CommonActivity parent, MainState state, String title)
  {
    super(parent, state, title);

    // Paint properties to draw text
    mText = new Paint();
    mText.setAntiAlias(true);
    mText.setColor(0xff442200);
    mText.setStyle(Paint.Style.FILL);
    mText.setTextSize(toPixel(14));
    mText.setTextAlign(Paint.Align.CENTER);

    // Paint properties to draw chart background
    mChartBkg = new Paint();
    mChartBkg.setAntiAlias(false);
    mChartBkg.setColor(0xffe0e044);
    mChartBkg.setStyle(Paint.Style.FILL);

    // Paint properties to draw chart bar
    mChartBar = new Paint();
    mChartBar.setAntiAlias(true);
    mChartBar.setColor(0xff884400);
    mChartBar.setStyle(Paint.Style.FILL);

    // Initialize the graphic space.
    mRtText = new Rect(0, 0, 0, 0);
    mRtChart = new Rect(0, 0, 0, 0);
    mRtBar = new RectF(0, 0, 0, 0);
    mRtDrawingBar = new RectF(0, 0, 0, 0);

    mVecData = new ArrayList<Integer>();

    // Observe DataStats object for data change
    ActivityMain.loader.mStats.addObserver(this);
  }

  /**
   * Get the total height of the frame, including the graph height.
   */
  @Override
  protected int getHeight()
  {
    int value = super.getHeight();

    mText.getTextBounds(DUMMY_TEXT, 0, DUMMY_TEXT.length(), mRtText);

    value += mRtText.height() + LINE_HEIGHT;
    value += PADDING;
    value += GRAPH_HEIGHT;
    value += PADDING;

    return value;
  }

  /**
   * Draw the text and the graph bars after drawing the title string.
   */
  @Override
  public void doDraw(Canvas canvas, Rect area)
  {
    super.doDraw(canvas, area);

    if (mVecData.isEmpty()) {
      return;
    }

    // Set the text
    final String altMinValue = Utils.getPreciseDistance(mPreference, mAltMinValue);
    final String altMaxValue = Utils.getPreciseDistance(mPreference, mAltMaxValue);
    final String altRange = altMinValue + " - " + altMaxValue;

    // Draw text
    final int textPosY = getTitleBottom() + mRtText.height();
    canvas.drawText(altRange, mRtShape.centerX(), textPosY, mText);

    // Set bar chart area
    mRtChart.set((int) mRtShape.left, (int) mRtShape.top, (int) mRtShape.right, (int) mRtShape.bottom);

    // Add space for the title
    mRtChart.top += PADDING + mRtTitle.height() + LINE_HEIGHT_FOR_TITLES;

    // Add space for the text
    mRtChart.top += mRtText.height() + LINE_HEIGHT;

    // Add some paddings
    mRtChart.top += PADDING;
    mRtChart.left += PADDING;
    mRtChart.right -= PADDING;
    mRtChart.bottom -= PADDING;

    // Draw background
    if (mBkgLinearGradient == null) {
      mBkgLinearGradient = new LinearGradient(
          mRtChart.left, mRtChart.top, mRtChart.left, mRtChart.bottom,
          0xffffff88, 0xffc8c844, Shader.TileMode.CLAMP);
    }

    mChartBkg.setShader(mBkgLinearGradient);
    canvas.drawRect(mRtChart, mChartBkg);
    mChartBkg.setShader(null);

    // Calculate the ratio between the chart area size to the existing data.
    final float barWidthRatio = (float) mRtChart.width() / (float) mVecData.size();
    final float barHeightRatio = mRtChart.height() / mAltMaxValue;

    // Draw the graph bars.
    // TODO Draw the bars according to a fixed width so that the chart area
    // depends on the data size. Support scrolling the chart area with finger.
    mRtBar.set(mRtChart);
    mRtBar.right = mRtBar.left + barWidthRatio;
    for (int i = 0; i < mVecData.size(); i++) {
      mRtBar.top = Math.round(mRtBar.bottom - (mVecData.get(i) * barHeightRatio));

      // Draw each bar
      mRtDrawingBar.set(mRtBar);
      mRtDrawingBar.left = Math.round(mRtBar.left);
      mRtDrawingBar.right = Math.round(mRtBar.right);

      canvas.drawRect(mRtDrawingBar, mChartBar);

      // Increase step
      mRtBar.left += barWidthRatio;
      mRtBar.right += barWidthRatio;
    }
  }

  @Override
  public void update(Observable observable, Object data)
  {
    if (mState.getCurrentUiMode() == Command.CMD_MODE_TRACKS) {
      if (observable == ActivityMain.loader.mStats) {
        if (data.equals(ActivityMain.loader.mStats.bUpdatedLocation)) {
          getData();
        }
        if (data.equals(ActivityMain.loader.mStats.bUpdatedMode)) {
          getData();
        }
      }
    }
  }

  private void getData()
  {
    mAltMaxValue = 0;
    mAltMinValue = 0;
    mVecData.clear();

    final TrackItem track = ActivityMain.loader.getSelectedTrack();
    if (track != null) {
      if (!track.isEmpty()) {
        final GeoPoint startPoint = track.vecTrackPoint.get(0);
        mAltMaxValue = startPoint.altitude;
        mAltMinValue = startPoint.altitude;

        synchronized (track.vecTrackPoint)
        {
          for (int i = 0; i < track.vecTrackPoint.size(); i++) {
            final GeoPoint point = track.vecTrackPoint.get(i);

            // Collect the altitude information from all track points.
            mVecData.add(point.altitude);

            if (point.altitude > mAltMaxValue)
              mAltMaxValue = point.altitude;   // find the max point.
            if (point.altitude < mAltMinValue)
              mAltMinValue = point.altitude;   // find the min point.
          }
        }
      }
    }
  }
}
